/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>

/*
 * internal data structs for processing external data format.
 */

/* constants.
 */
#define MAXNEST 20 /* max number of nested include files */

/* MAXBUF controls the size of one line of a dx file. Since this could be
   a really long string perhaps this isn't the best way to do it. */

#define MAXBUF 4097  /* max length of a single input token */
#define MAXRANK 50   /* max rank for data items */
#define MAXTERMS 100 /* max terms in mesh or product array */

/* as objects are created, they are added to a linked list of objects,
 *  with an id associated with each.
 */
struct objlist
{
  int id;                /* unique per input file */
  Object o;              /* if != NULL, actual object */
  char *name;            /* if named, the name */
  int oused;             /* whether object is really used in the file */
  int odelete;           /* what to do with object when done */
  int nrefs;             /* size of following list */
  struct objlist **refs; /* list of objects referenced by this one */
  struct objlist *next;  /* linked list of all objects in file */
  struct getby *gp;      /* if a remote id, the info for remote */
};

/* odelete values.
 *  what to do at the end when deleting the dictionary.  this is used to
 *  keep the top level objects without monkeying with the ref counts.
 */
#define OBJ_CANDELETE 0
#define OBJ_NODELETE 1

/* oused values
 *  in onepass, all objects are created at the time they are encountered,
 *  and at the end all unreferenced objects are deleted.
 *  in twopass, all objects are identified as being referenced or not and
 *  in the second pass the unused objects are not created.
 */
#define OBJ_UNUSED 0
#define OBJ_USED 1

#define NAMEATTR "name"

/* local object id (same file), remote file id or either
 */
#define ID_LOCAL 1
#define ID_REMOTE 2
#define ID_EITHER 3

/*
 * dictionary section
 */

/* blocksize for local memory allocates
 */
#define LOCALSTORBLOCK 8192

/* dictionary entry for variable name -> unique identifier
 */
struct dinfo
{
  PseudoKey key;  /* psuedokey based on string contents */
  char *contents; /* actual key value */
  int type;       /* class of token */
  int value;      /* system generated id for object aliases */
};

/* dictionary entry for keyword -> identifier
 */
struct kinfo
{
  PseudoKey key;  /* psuedokey based on string contents */
  char *contents; /* actual key value */
  int value;      /* keyword token id */
};

struct localstor
{
  int bytesleft;                 /* bytes are left to be allocated; 0==full */
  int nextbyte;                  /* next available byte in block */
  struct localstor *next;        /* next block like this; NULL for end */
  char contents[LOCALSTORBLOCK]; /* actual local storage */
};

struct dict
{
  HashTable dicttab;           /* hash table for user strings */
  HashTable keytab;            /* hash table for keywords */
  struct localstor *localdict; /* local storage for strings */
  int nextid;                  /* unique system-allocated ids */
};

/* object ids - either user defined or generated by the system.
 */
#define USER_ID( x ) ( ( x + 1 ) << 1 )
#define SYS_ID( x ) ( ( x + 1 ) << 1 | 1 )

/*
 * return by name vs. return by number
 */
struct getby
{
  char *fname;      /* remote filename, if needed - must free */
  int which;        /* import by name or by number */
  int num;          /* single number */
  char **namelist;  /* null terminated namelist (uses buf) */
  int *numlist;     /* -1 terminated numlist (uses buf) */
  Pointer *gbuf;    /* storage for lists - must free */
  int seriesflag;   /* which of start/end/delta has been set */
  int serieslim[3]; /* start/end/delta frame numbers */
};

/*
 * values for 'which'
 */
#define GETBY_NONE 0     /* not set yet */
#define GETBY_NAME 1     /* named object list */
#define GETBY_NUM 2      /* single object number or byte offset */
#define GETBY_NUMLIST 3  /* object number list */
#define GETBY_LINES 4    /* line number offset */
#define GETBY_ID 5       /* internal dictionary id */
#define GETBY_ALLNAMES 6 /* all named objects */

/*
 * series limit flags
 */
#define SL_START 0x0001
#define SL_END 0x0002
#define SL_DELTA 0x0004

/* ascii-input-line-number to byte-offset-in-file translation list.
 *
 *  could be used both ways (for finding a line number given a byte offset),
 *  but right now it's being used for converting a line number to a byte
 *  offset in the file so 'data line #' can be used to say where the
 *  ascii data starts in a file.  i don't know how to count lines when
 *  there is binary data follows.  praps the default for export ascii should
 *  be line nos and for binary should be bytes.
 */
struct lines
{
  int bytesalloc; /* allocation size is maxlcount * sizeof(int) */
  int lcount;     /* current max line count */
  int *linelist;  /* byte offset of each line from top of file */
};

/*
 * structure the input tokenizer (lexinput) routine returns.
 */
typedef union
{
  int id;
  unsigned char c;
  int i;
  float f;
  double d;
} Token;

struct tinfo
{
  int class;    /* see list below */
  int subclass; /* more specific */
  Token token;  /* value.  type depends on class and context */
};

/* token class:                    subclass:            token value:    */
#define NUMBER 1       /* number type          numeric value   */
#define KEYWORD 2      /* none                 keyword id      */
#define BRACKET 3      /* bracket type         dictionary id   */
#define STRING 4       /* none                 dictionary id   */
#define LEXERROR 5     /* error type           none            */
#define NOTASCII 6     /* none                 none            */
#define ALIAS 7        /* object id            dictionary id   */
#define PUNCT 8        /* punctuation type     none            */
#define IDENTIFIER 9   /* none                 dictionary id   */
#define ENDOFHEADER 10 /* none                 none            */

/* subclasses of number */
#define INTEGER 1
#define FLOAT 2
#define DOUBLE 3
#define CHAR 4

/* subclasses of bracketed strings - not currently used */
#define PAREN 1
#define SQUARE 2
#define CURLY 3
#define ANGLE 4

/* subclasses of error */
#define BADINPUT -1
#define BADQUOTE -2
#define BADNUMBER -3
#define BADCOMMA -4
#define BADBRACKET -5
#define BADLENGTH -6

/* subclasses of punctuation */
#define COMMA 1
#define SEMICOLON 2
#define COLON 3
#define NEWLINE 4
#define OTHER 9
#define UNKNOWN -1

/* info about how to parse.
 *
 * maybe this is going to need code for 'identifier' in the mustmatch
 *  section so that file,number or file,name will parse as one dictionary
 *  entry and get one identifier.
 *
 */
struct pinfo
{
  int tonextline; /* return at start of next line */
  int skippunct;  /* punctuation (separators) are ok to skip */
  int mustmatch;  /* if the next token type is known already */

  int nbytes;  /* for skip, skip count */
  int nodict;  /* for string data, don't put in dictionary */
  int skipnum; /* for numeric data, don't do the conversion */

  char *inbuf; /* one token input buffer */
  int incount; /* number of characters in that buffer */

  char delim;      /* current delimiter (squote, dquote, bracket, etc) */
  int byteoffset;  /* current byte offset */
  int lineno;      /* current line offset */
  int prevlineno;  /* line offset when parse was started */
  int startlineno; /* line number where current object defn starts */
  struct lines l;  /* bytes offset to line number struct */

  /* plus what?  */
};

/*
 * one of these structures per open input file
 */
struct finfo
{
  char *fname;        /* input filename */
  FILE *fd;           /* fopen file descriptor */
  struct getby gb;    /* list of objects to import, and series limits */
  struct tinfo t;     /* current input token */
  struct pinfo p;     /* current parse state */
  int recurse;        /* recurse level for included files */
  int dformat;        /* default data format flags */
  int denorm_fp;      /* i860 binary data only: zero'd denormalized floats */
  int bad_fp;         /* i860 binary data only: zero'd NaN and Infinities */
  int onepass;        /* set if we can't seek backwards (eg it's a socket) */
  int headerend;      /* byte offset of end of header section */
  HashTable ht;       /* hash table for objects by objectid */
  struct objlist *ol; /* list of all objects created or referenced */
  struct dict *d;     /* dictionary for this file */
  int activity;       /* whether we are making objects or just parsing ids */
  Object curobj;      /* object currently under construction */
  int curid;          /* id of current object */
};

/*
 * data file format flags
 */
#define D_BYTES 0x0007
#define D_MSB 0x0001
#define D_LSB 0x0002
#define D_NATIVE 0x0004

#define D_FORMATS 0x0070
#define D_IEEE 0x0010
#define D_XDR 0x0020
#define D_TEXT 0x0040

#define D_FILES 0x0700
#define D_FOLLOWS 0x0100
#define D_ONE 0x0200
#define D_TWO 0x0400

/* activity flag options:
 *
 * two pass:
 *  identifying which objects use others and which ones are actually
 *  going to be imported.  filling byte offset/line number table.
 *  skipping binary data follows arrays.
 *
 *  making the used objects
 *
 * one pass:
 *  making all objects and discarding unused ones at the end
 */
#define IDENTIFY_OBJS 1
#define MAKE_USED_OBJS 2
#define MAKE_ALL_OBJS 3

/*
 * object list ptr and object id from that list.
 */
struct objectid
{
  struct objlist *ol;
  int id;
};

/*
 * keywords for dictionary
 */

/* used in keyword list below.  good words > 0, errors < 0 */
#define KW_OBJECT 1
#define KW_GROUP 2
#define KW_ARRAY 3
#define KW_FIELD 4
#define KW_STRING 5
#define KW_TRANSFORM 6
#define KW_MATRIX 7
#define KW_LIGHT 8
#define KW_CLIPPED 9
#define KW_SCREEN 10
#define KW_FILE 11
#define KW_ALIAS 12
#define KW_SERIES 13
#define KW_ATTRIBUTE 14
#define KW_VALUE 15
#define KW_COMPONENT 16
#define KW_MEMBER 17
#define KW_CLASS 18
#define KW_TYPE 19
#define KW_CHAR 20
#define KW_SHORT 21
#define KW_INTEGER 22
/* #define              23 */
#define KW_HYPER 24
#define KW_FLOAT 25
#define KW_DOUBLE 26
#define KW_CATEGORY 27
#define KW_REAL 28
#define KW_COMPLEX 29
#define KW_QUATERNION 30
#define KW_RANK 31
#define KW_SHAPE 32
#define KW_COUNT 33
/* #define              34 */
#define KW_DATA 35
#define KW_XDR 36
#define KW_ASCII 37
#define KW_IEEE 38
#define KW_FOLLOWS 39
#define KW_REGULARARRAY 40
#define KW_PRODUCTARRAY 41
#define KW_MESHARRAY 42
#define KW_PATHARRAY 43
#define KW_CAMERA 44
#define KW_DIRECTION 45
#define KW_LOCATION 46
#define KW_POSITION 47
#define KW_SIZE 48
#define KW_COLOR 49
#define KW_COMPOSITE 50
#define KW_NAME 51
#define KW_XFORM 52
#define KW_OF 53
#define KW_BY 54
#define KW_TIMES 55
#define KW_PLUS 56
#define KW_TERM 57
#define KW_ORIGIN 58
#define KW_DELTAS 59
#define KW_GRID 60
#define KW_GRIDPOSITIONS 61
#define KW_GRIDCONNECTIONS 62
#define KW_DISTANT 63
#define KW_LOCAL 64
#define KW_FROM 65
#define KW_TO 66
#define KW_WIDTH 67
#define KW_HEIGHT 68
#define KW_RESOLUTION 69
#define KW_ASPECT 70
#define KW_UP 71
#define KW_NUMBER 72
#define KW_MSB 73
#define KW_LSB 74
#define KW_MODE 75
#define KW_BINARY 76
#define KW_MESHOFFSETS 77
#define KW_DEFAULT 78
#define KW_LINES 79
#define KW_ANGLE 80
#define KW_AMBIENT 81
#define KW_WORLD 82
#define KW_VIEWPORT 83
#define KW_PIXEL 84
#define KW_BEHIND 85
#define KW_INSIDE 86
#define KW_INFRONT 87
#define KW_STATIONARY 88
#define KW_ORTHOGRAPHIC 89
#define KW_PERSPECTIVE 90
#define KW_NAMED 91
#define KW_CONSTANTARRAY 92
#define KW_SIGNED 93
#define KW_UNSIGNED 94
#define KW_MULTIGRID 95
/* add more here, and match with dict struct */
#define KW_END 9999
#define KW_NULL -1

/* bad return from dictionary lookup */
#define BADINDEX 0

/* force correct casts swab routines */
/* these use the (destination, source, ... ) parm order */
#define SWAB( x, y, z ) \
  _dxfByteSwap( (void *)x, (void *)y, ( int )( z ) / 2, TYPE_SHORT )
#define SWAW( x, y, z ) \
  _dxfByteSwap( (void *)x, (void *)y, ( int )( z ) / 4, TYPE_INT )
#define SWAD( x, y, z ) \
  _dxfByteSwap( (void *)x, (void *)y, ( int )( z ) / 8, TYPE_DOUBLE )

/* Byte order */
typedef enum
{
  BO_UNKNOWN = 1,
  BO_MSB = 2,
  BO_LSB = 3
} ByteOrder;

extern Error _dxfByteSwap( void *, void *, int, Type );
extern ByteOrder _dxfLocalByteOrder( void );
#define LOCAL_BYTEORDER _dxfLocalByteOrder()

/* shorthand for common routines.  should these be real entry points?
 * these are going to be more efficient but make debugging more complicated.
 */
#define next_class( f, class ) _dxfnexttoken( f, class, NULL, NULL )
#define next_subclass( f, subclass ) _dxfnexttoken( f, NULL, subclass, NULL )
#define next_id( f, id ) _dxfnexttoken( f, NULL, NULL, id )
#define next_token( f, class, subclass, id ) \
  _dxfnexttoken( f, class, subclass, id )
#define nextkeywordis( f, keyword ) _dxfmatchid( f, KEYWORD, keyword, 1 )
#define next_string( f ) _dxfisnexttoken( f, STRING, NULL, NULL )

#define skipkeyword( f ) _dxfmatchanysub( f, KEYWORD, NULL, NULL )
#define match_keyword( f, keyword ) _dxfmatchid( f, KEYWORD, keyword, 0 )
#define match_punct( f, type ) _dxfmatchsaysub( f, PUNCT, type, NULL )

#define get_keyword( f, keyword ) _dxfmatchanysub( f, KEYWORD, NULL, keyword )
#define get_string( f, string ) _dxfmatchanysub( f, STRING, NULL, string )
#define get_punct( f, type ) _dxfmatchanysub( f, PUNCT, type, NULL )
#define get_ident( f, id ) _dxfmatchanysub( f, IDENTIFIER, NULL, id )

#define get_number( f, type, val ) _dxfmatchnumber( f, type, val )

#define get_byte( f, val ) _dxfmatchbyte( f, val )
#define get_ubyte( f, val ) _dxfmatchubyte( f, val )
#define get_short( f, val ) _dxfmatchshort( f, val )
#define get_ushort( f, val ) _dxfmatchushort( f, val )
#define get_int( f, val ) _dxfmatchint( f, val )
#define get_uint( f, val ) _dxfmatchuint( f, val )
#define get_float( f, val ) _dxfmatchfloat( f, val )
#define get_double( f, val ) _dxfmatchdouble( f, val )

/* prototypes
 */

extern Error _dxfinitparse( struct finfo *f );
extern Error _dxfresetparse( struct finfo *f );
extern void _dxfdeleteparse( struct finfo *f );
extern void _dxfsetstartline( struct finfo *f );
extern int _dxfgetstartline( struct finfo *f );
extern void _dxfsetprevline( struct finfo *f );
extern int _dxfgetprevline( struct finfo *f );
extern int _dxfgetlineno( struct finfo *f );
extern Error _dxfnextline( struct finfo *f );
extern Error _dxfendnotascii( struct finfo *f );
extern void _dxfsetnexttype( struct finfo *f, int type );
extern void _dxfsetskipnum( struct finfo *f, int type );
extern void _dxfsetdictstringmode( struct finfo *f, int value );
extern char *_dxfgetstringinfo( struct finfo *f, int *len );
extern Error _dxfgetstringnodict( struct finfo *f );
extern Error _dxfset_headerend( struct finfo *f );
extern Error _dxfsetparse( struct finfo *f, long byteoffset, int lines,
                           int lineno );

extern Error _dxfnexttoken( struct finfo *f, int *class, int *subclass,
                            int *id );
extern Error _dxfisnexttoken( struct finfo *f, int *class, int *subclass,
                              int *id );
extern Error _dxfmatchbyte( struct finfo *f, byte *p );
extern Error _dxfmatchubyte( struct finfo *f, ubyte *p );
extern Error _dxfmatchshort( struct finfo *f, short *p );
extern Error _dxfmatchushort( struct finfo *f, ushort *p );
extern Error _dxfmatchint( struct finfo *f, int *p );
extern Error _dxfmatchuint( struct finfo *f, uint *p );
extern Error _dxfmatchfloat( struct finfo *f, float *p );
extern Error _dxfmatchdouble( struct finfo *f, double *p );

extern Error _dxfmatchsaysub( struct finfo *f, int class, int subclass,
                              int *id );
extern Error _dxfmatchanysub( struct finfo *f, int class, int *subclass,
                              int *id );
extern Error _dxfmatchnumber( struct finfo *f, int *subclass, Token *id );
extern Error _dxfmatchid( struct finfo *f, int class, int id, int noparse );

extern Error _dxfinitfinfo( struct finfo *f );
extern void _dxffreefinfo( struct finfo *f );
extern void _dxfdupfinfo( struct finfo *f1, struct finfo *f2 );

extern int _dxfiskeyword( struct dict *d, char *word );
extern char *_dxflookkeyword( int id );

extern Error _dxfinitdict( struct dict *d );
extern Error _dxfdeletedict( struct dict *d );
extern int _dxfputdict( struct dict *d, char *word );
extern int _dxflookdict( struct dict *d, char *word );
extern char *_dxfdictname( struct dict *d, int slot );
extern Error _dxfgetdictinfo( struct dict *d, int slot, int *type, int *value );
extern Error _dxfsetdictalias( struct dict *d, int slot, int *value );
extern Error _dxfgetdictalias( struct dict *d, int alias, int *value );
extern int _dxfgetuniqueid( struct dict *d );

extern FILE *_dxfopen_dxfile( char *inname, char *auxname, char **outname,
                              char *ext );
extern Error _dxfclose_dxfile( FILE *fptr, char *filename );
extern Error _dxfparse_file( struct finfo *f, Object *retobj );

extern Error _dxfreadarray_binary( struct finfo *f, Array a, int format );
extern Error _dxfreadarray_xdr( FILE *fd, Array a );
extern Error _dxfreadarray_text( struct finfo *f, Array a );
extern Error _dxfskiparray_binary( struct finfo *f, int items, int itemsize );
extern Error _dxfskiparray_xdr( FILE *fd, int items, int itemsize );
extern Error _dxfskiparray_text( struct finfo *f, int items, Type t );
extern Error _dxfreadoffset( struct finfo *f, Array a, int offset, int type );
extern Error _dxfreadremote( struct finfo *f, Array a, int id, int type );

extern Error _dxfinitobjlist( struct finfo *f );
extern Error _dxfdeleteobjlist( struct finfo *f );
extern Error _dxfaddobjlist( struct finfo *f, int id, Object o, char *name,
                             int start );
extern Error _dxflookobjlist( struct finfo *f, int id, Object *o, char **name );
struct getby **_dxfgetobjgb( struct finfo *f, int id );
extern Error _dxfsetobjptr( struct finfo *f, int id, Object o );
extern Error _dxfsetobjused( struct finfo *f, int id );
extern Error _dxfisobjused( struct finfo *f, int id );
extern Error _dxfobjusesobj( struct finfo *f, int id, int refd_id );

extern Object _dxfnamedobjlist( struct finfo *f, char **namelist );
extern Object _dxfmarknamedobjlist( struct finfo *f, char **namelist );
extern Object _dxfnumberedobjlist( struct finfo *f, int *numlist, int idflag );
extern Object _dxfmarknumberedobjlist( struct finfo *f, int *numlist,
                                       int idflag );

extern Error _dxflexinput( struct finfo *fp );
extern char *_dxfprtoken( struct tinfo *t, struct dict *d );

extern Error _dxfskip_object( struct finfo *fp );
extern Error _dxfskip_object_or_attr( struct finfo *fp );

/* utility routines
 */
extern Error _dxfValidate( Field f );
extern Error DXColorNameToRGB( char *, RGBColor * );

/* routines defined in edf*.c */
Error _dxflook_objident( HashTable, Object, int *, int * );
Error _dxfinit_objident( HashTable * );
Error _dxfdelete_objident( HashTable );
Error _dxfadd_objident( HashTable, Object, int, int );

#if !defined( DXD_STANDARD_IEEE )
/*
 * Floating point denormalization checks for machines which don't support
 * IEEE denormalized floating point values.
 */
extern void _dxfdouble_denorm( int *, int, int *, int * );
extern void _dxffloat_denorm( int *, int, int *, int * );
#endif

/* should debugging messages be compiled in?  0=no, 1=yes
 */

#define DEBUG_MSG 0
